package com.yunxi.poc.starbucks.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yunxi.poc.starbucks.common.BizConstant;
import com.yunxi.poc.starbucks.entity.Order;
import com.yunxi.poc.starbucks.entity.TStoreCapacityAvg;
import com.yunxi.poc.starbucks.entity.Tb1TransactionSale;
import com.yunxi.poc.starbucks.mapper.TStoreCapacityAvgMapper;
import com.yunxi.poc.starbucks.service.IOrderService;
import com.yunxi.poc.starbucks.service.ITStoreCapacityAvgService;
import com.yunxi.poc.starbucks.service.ITb1TransactionSaleService;
import com.yunxi.poc.starbucks.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author shiyuan.xlc
 * @since 2021-09-06
 */
@Service
public class TStoreCapacityAvgServiceImpl extends ServiceImpl<TStoreCapacityAvgMapper, TStoreCapacityAvg> implements ITStoreCapacityAvgService {

    private final static Logger logger = LoggerFactory.getLogger(TStoreCapacityAvgServiceImpl.class);

    @Resource
    IOrderService orderService;

    @Resource
    ITb1TransactionSaleService transactionSaleService;

    @Resource
    ITStoreCapacityAvgService storeCapacityAvgService;

    @Override
    public void calulateCapacity(String storeId, LocalDate start, LocalDate end, List<LocalDate> days) {
        // 1. 从门店经营时间开始，每半个小时划分区间
        // 2. 计算每个区间，每一笔线上订单的完成时间 pay_date  make_finish_date~pay_date
        // 3. 求2的平均值
        // 4. 计算区间的产能

        List<LocalDate> dayList = new ArrayList<>(days);
        for (int i = 0; i <= ChronoUnit.DAYS.between(start, end); i++) {
            dayList.add(start.plusDays(i));
        }

        dayList.parallelStream().forEach(day -> {
            // 当天线上订单
            QueryWrapper<Order> orderWrapper = new QueryWrapper<>();
            orderWrapper.select("pay_date", "make_finish_date");
            orderWrapper.eq("store_id", storeId);
            orderWrapper.ge("create_date", day.atStartOfDay());
            orderWrapper.le("create_date", day.plusDays(1).atStartOfDay().minusSeconds(1));
            orderWrapper.eq("status", "5");     // 已完成
            orderWrapper.isNotNull("pay_date");
            orderWrapper.isNotNull("make_finish_date");
            List<Order> todayOrders = this.orderService.list(orderWrapper);
            todayOrders.sort(Comparator.comparing(Order::getPayDate));
            // 保留耗时30min内的数据
            todayOrders = todayOrders.parallelStream()
                    .filter(e -> Math.abs(ChronoUnit.SECONDS.between(e.getPayDate(), e.getMakeFinishDate())) <= 30 * 60 && e.getMakeFinishDate().compareTo(e.getPayDate()) > 0)
                    .collect(Collectors.toList());

            if (CollectionUtils.isEmpty(todayOrders)) return;

            // 当天线下订单
            QueryWrapper<Tb1TransactionSale> queryWrapperTrans = new QueryWrapper<>();
            queryWrapperTrans.select("sale_item_quantity", "sale_datetime");
            queryWrapperTrans.eq("global_store_number", storeId);
            queryWrapperTrans.ge("sale_datetime", day.atStartOfDay());
            queryWrapperTrans.le("sale_datetime", day.plusDays(1).atStartOfDay().minusSeconds(1));
            queryWrapperTrans.last("AND sale_item_code "
                    + "in ( SELECT distinct sale_item_code FROM saleitem_with_reportcategory "
                    + "where report_category in ("
                    + BizConstant.REPORT_CATEGORY.stream().map(e -> "'" + e + "'").collect(Collectors.joining(","))
                    + ") )");
            List<Tb1TransactionSale> todayTrans = this.transactionSaleService.list(queryWrapperTrans);

            // 获取所有时间对
            List<List<LocalDateTime>> timePairAfter = DateUtil.getTimePairAfter(todayOrders.get(0).getPayDate());
            double avgCostTimeSecLast = 0;
            for (List<LocalDateTime> timePair : timePairAfter) {
                LocalDateTime pStart = timePair.get(0);
                LocalDateTime pEnd = timePair.get(1);
                double avgCostTimeSec = todayOrders.parallelStream()
                        .filter(e -> e.getPayDate().compareTo(pStart) >= 0 && e.getPayDate().compareTo(pEnd) < 0)
                        .mapToLong(e -> Math.abs(ChronoUnit.SECONDS.between(e.getPayDate(), e.getMakeFinishDate())))
                        .average()
                        .orElse(0);
                double sales = todayTrans.parallelStream()
                        .filter(e -> e.getSaleDatetime().compareTo(pStart) >= 0 && e.getSaleDatetime().compareTo(pEnd) < 0 && e.getSaleItemQuantity().compareTo(BigDecimal.valueOf(0)) > 0)
                        .mapToDouble(e -> e.getSaleItemQuantity().doubleValue())
                        .sum();
                double capacity = sales / (30 + ((avgCostTimeSec - avgCostTimeSecLast) / 60));
                avgCostTimeSecLast = avgCostTimeSec;

                TStoreCapacityAvg storeCapacityAvg = new TStoreCapacityAvg();
                storeCapacityAvg.setStoreId(storeId);
                storeCapacityAvg.setBusinessDay(day);
                storeCapacityAvg.setStart(timePair.get(0).toLocalTime());
                storeCapacityAvg.setEnd(timePair.get(1).toLocalTime());
                storeCapacityAvg.setMax20minSales(String.valueOf(capacity));
                storeCapacityAvg.setDailySales(String.valueOf(sales));
                storeCapacityAvg.setAvgCost(String.valueOf(avgCostTimeSec));
                this.storeCapacityAvgService.save(storeCapacityAvg);
            }
        });
    }
}
